home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994…tember: Reference Library / Dev.CD Sep 94.toast / Periodicals / develop / develop Issue 19 / develop 19 code / Adding GX Printing to QD Apps / Simple Sample GX ƒ / menus & windows.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-15  |  23.5 KB  |  935 lines  |  [TEXT/KAHL]

  1. /*********************************************************************
  2.  
  3.     menus & windows.c
  4.     
  5.     This file contains the menu and window handling code for the
  6.     QuickDraw GX aware sample, "Simple Sample GX."
  7.     
  8.     Additional info can be found in the related develop #19 article,
  9.     "Adding QuickDraw GX Printing to QuickDraw Applications."
  10.  
  11.     Dave Hersey, Apple Developer Technical Support.
  12.     
  13.     ——————— Edit Trail ———————
  14.     
  15.     constructed:                                    1/22/94  - dmh
  16.     cleaned up for 2nd draft of develop article:    3/10/94  - dmh
  17.     cleaned up for final:                            4/14/94  - dmh
  18.     
  19. *********************************************************************/
  20.  
  21. #include "Simple Sample.h"
  22.  
  23.  
  24. /************************************************************
  25.   MyCreateDocument - This routine is called to create a new
  26.   document.
  27.  
  28. *************************************************************/
  29.  
  30. OSErr MyCreateDocument(char *docTitle, MyDocumentPtr *createdDocument)
  31. {
  32.     OSErr            err;
  33.     WindowPtr        documentWindow;
  34.     long            newPage;
  35.  
  36.     *createdDocument = nil;
  37.  
  38. // Create a window for our document.
  39.  
  40.     documentWindow = (WindowPtr) NewCWindow(nil, &gWindowRect, (ConstStr255Param) docTitle, false, noGrowDocProc, (WindowPtr)-1L, true, 0L);
  41.     require_action(documentWindow, CouldNotCreateWindow, err = MemError(););
  42.  
  43. // Initialize our private data for the document.
  44.  
  45.     *createdDocument = (MyDocumentPtr) NewPtrClear(sizeof(MyDocumentRec));
  46.     require_action(*createdDocument, CouldNotCreateDocRec, err = MemError(););
  47.  
  48. /*
  49.     If QuickDraw GX is present, create a new job object and install an application
  50.     override for the gxPrintingEvent message.  Note that you only need to have
  51.     this message overridden while print dialogs are displayed, but overriding it
  52.     here doesn't hurt.
  53.     
  54.     If QuickDraw GX is not present, simply create a print handle.
  55. */
  56.  
  57.     if (gGXIsPresent)
  58.     {
  59.         err = GXNewJob(&(*createdDocument)->documentJob);
  60.  
  61.         if (err == noErr)
  62.             GXInstallApplicationOverride((*createdDocument)->documentJob,
  63.                                          gxPrintingEvent,
  64.                                          MyPrintingEventOverride);
  65.     }
  66.     else
  67.     {
  68.         (*createdDocument)->documentPrintHdl = (THPrint) NewHandle(sizeof(TPrint));
  69.         err = MemError();
  70.  
  71.         if (!err)
  72.         {
  73.             PrOpen();
  74.             PrintDefault((*createdDocument)->documentPrintHdl);
  75.             PrClose();
  76.         }
  77.     }
  78.  
  79. /*
  80.     If there were no errors, add 1 page to the document, and
  81.     store a reference to our private data in the document's
  82.     window's refCon field.
  83. */
  84.  
  85.     nrequire(err, CouldNotCreatePrintStuff);
  86.     
  87.     (*createdDocument)->numPages = 0;
  88.     (*createdDocument)->documentWindow = documentWindow;
  89.     (*createdDocument)->documentFSSpec.name[0] = 0;        // Indicates that document has never
  90.                                                         // been saved.
  91.     if (docTitle[0] > 31)
  92.         docTitle[0] = 31;
  93.     
  94.     BlockMove(&docTitle[0], &(*createdDocument)->documentTitle[0], (long) docTitle[0] +1);
  95.     newPage = 0;
  96.     err = MyInsertPage(*createdDocument, &newPage);
  97.     (*createdDocument)->curPage = newPage;
  98.  
  99. // Set the refCon to point to our document info structure.
  100.  
  101.     nrequire(err, CouldNotInsertPage);
  102.     SetWRefCon(documentWindow, (long) *createdDocument);
  103.     require(err, NoProblems);
  104.  
  105. CouldNotInsertPage:
  106.     if (gGXIsPresent)
  107.         GXDisposeJob((*createdDocument)->documentJob);
  108.     else
  109.         DisposHandle((Handle) (*createdDocument)->documentPrintHdl);
  110.  
  111. CouldNotCreatePrintStuff:
  112.     DisposePtr((Ptr) *createdDocument);
  113.  
  114. CouldNotCreateDocRec:
  115.     DisposeWindow(documentWindow);
  116.  
  117. CouldNotCreateWindow:
  118. NoProblems:
  119.     return err;
  120. }
  121.  
  122.  
  123. /************************************************************
  124.   MyDisposeDocument - This routine is called when we need to
  125.   dispose of a window.
  126.  
  127. *************************************************************/
  128.  
  129. void MyDisposeDocument(MyDocumentPtr whichDocument)
  130. {
  131.     long        numPages, pg;
  132.     WindowPtr    docWindow;
  133.     
  134. // Dispose of our private data for each page of this document.
  135.  
  136.     numPages = whichDocument->numPages;
  137.  
  138.     for (pg = numPages; pg >= 1; pg--)
  139.         MyDisposePage(whichDocument, pg);
  140.  
  141. /*
  142.     Dispose of our document's print record and job object,
  143.     if any.  Finally dispose of the document's window and
  144.     the pointer to our document's private data.
  145. */
  146.     if (whichDocument->documentPrintHdl != nil)
  147.         DisposHandle((Handle) whichDocument->documentPrintHdl);
  148.     
  149.     if (whichDocument->documentJob != nil)
  150.         GXDisposeJob(whichDocument->documentJob);
  151.  
  152.        DisposeWindow(whichDocument->documentWindow);
  153.     DisposePtr((Ptr) whichDocument);
  154. }
  155.  
  156.  
  157. /************************************************************
  158.   MyInsertPage - This routine is called when we need to add
  159.   a page to a document.  The page is added AFTER the page
  160.   number passed (1-based).  If whichPg is greater than the
  161.   last page of the document, the new page is added to the
  162.   end of the document.  If whichPg is less than 1, the page
  163.   is added to the beginning of the doc.  The page number of
  164.   the new page is returned in whichPg.
  165.  
  166. *************************************************************/
  167.  
  168. OSErr MyInsertPage(MyDocumentPtr whichDocument, long *whichPage)
  169. {
  170.     OSErr        err = noErr;
  171.     long        numPages, aPage;
  172.     long        newSize;
  173.  
  174. // Pin the number of the page to add to the range (1, numPages +1).
  175.  
  176.     numPages = whichDocument->numPages;
  177.     *whichPage = (*whichPage < 1)? 1: (*whichPage < numPages)? *whichPage +1: numPages +1;
  178.  
  179. /*
  180.     If QuickDraw GX is present, set this page's format to nil so
  181.     that we use the default job format.
  182. */
  183.     if (gGXIsPresent)
  184.         whichDocument->pageFormat[*whichPage -1] = nil;
  185.  
  186. /*
  187.     Do whatever you need to do to add page data here.
  188.     .
  189.     .
  190.     .
  191.     
  192. */
  193.  
  194.     numPages = ++whichDocument->numPages;
  195.     return err;
  196. }
  197.  
  198.  
  199. /************************************************************
  200.   MyDisposePage - This routine is called when we need to
  201.   dispose of a page in a document.
  202.  
  203. *************************************************************/
  204.  
  205. void MyDisposePage(MyDocumentPtr whichDocument, long whichPage)
  206. {
  207.     long        numPages, pageNum;
  208.     long        newSize;
  209.  
  210. // Idiot control.
  211.  
  212.     if (whichPage > whichDocument->numPages) return;    // ?!  There aren't that many pages!!
  213.     if (whichPage < 1) return;                            // ?!  Page numbers start at 1!!
  214.  
  215. /*
  216.     If GX is present and we have a page format for this
  217.     page, dispose of the format.
  218. */
  219.     if (gGXIsPresent && (whichDocument->pageFormat[whichPage -1] != nil))
  220.         GXDisposeFormat(whichDocument->pageFormat[whichPage -1]);
  221.  
  222. /*
  223.     Do whatever you need to do to remove page data here.
  224.     .
  225.     .
  226.     .
  227.     
  228. */
  229.  
  230. // We now have one less page in our document.
  231.  
  232.     numPages = --whichDocument->numPages;
  233. }
  234.  
  235.  
  236. /************************************************************
  237.   MyUpdateWindow - This routine simply updates the passed
  238.   window.
  239.  
  240. *************************************************************/
  241.  
  242. void MyUpdateWindow(WindowPtr whichWindow)
  243. {
  244.     GrafPtr        oldPort;
  245.  
  246. // Update the indicated window.
  247.  
  248.     if (((WindowPeek) whichWindow)->windowKind == userKind)
  249.     {
  250.         GetPort(&oldPort);
  251.         SetPort(whichWindow);
  252.         BeginUpdate(whichWindow);
  253.         MyDrawContents(whichWindow);
  254.         EndUpdate(whichWindow);
  255.         SetPort(oldPort);
  256.     }
  257. }
  258.  
  259.  
  260. /************************************************************
  261.   MyDrawContents - This routine draws the contents of a
  262.   window.  Note that this same code is used to draw during
  263.   printing.  All we do in this code is make a bunch of
  264.   QuickDraw calls to draw our document's pages.
  265.  
  266. *************************************************************/
  267.  
  268. void MyDrawContents(WindowPtr whichWindow)
  269. {
  270.     MyDocumentPtr    windowDoc;
  271.     PicHandle        drawPict;
  272.     Rect            drawRect, drawRect2;
  273.     short            fNum, i, lineInc, hCenter, picWidth, picHeight;
  274.     short            oldResFile;
  275.     FontInfo        fInfo;
  276.     Handle            iconHdl;
  277.     BitMap            iconBitMap;
  278.     Str255            pStr;
  279.     Point            where;
  280.     GrafPtr            curPort;
  281.  
  282. //    Preserve the current resource file in case we're printing.
  283.  
  284.     oldResFile = CurResFile();
  285.     windowDoc = MyGetDocPtr(whichWindow);
  286.  
  287. // Draw a red QuickDraw rectangle.
  288.  
  289.     ForeColor(redColor);
  290.     SetRect(&drawRect, 20, 20, 150, 150);
  291.     FrameRect(&drawRect);
  292.  
  293. // Draw a blue QuickDraw oval.
  294.  
  295.     ForeColor(blueColor);
  296.     OffsetRect(&drawRect, 40, 40);
  297.     FrameOval(&drawRect);
  298.  
  299. // Draw a black QuickDraw line with a 4x4 pen.
  300.  
  301.     ForeColor(blackColor);
  302.     PenSize(4, 4);
  303.     MoveTo(drawRect.left, drawRect.top);
  304.     LineTo(drawRect.right, drawRect.bottom);
  305.     PenSize(1, 1);
  306.  
  307. // Draw some QuickDraw text with various faces.
  308.  
  309.     GetFNum("\pNew York", &fNum);
  310.     TextFont(fNum);
  311.     TextSize(10);
  312.     GetFontInfo(&fInfo);
  313.     lineInc = fInfo.ascent + fInfo.leading + fInfo.descent;
  314.     TextFace(bold);
  315.     MoveTo(220, 40);
  316.     DrawString("\pFor Sale: ");
  317.     TextFace(0);
  318.     DrawString("\pEnglish sheepdog.  ");
  319.     TextFace(underline);
  320.     DrawString("\pCompletely");
  321.     TextFace(0);
  322.     MoveTo(220, 40 + lineInc);
  323.     DrawString("\phouse-broken, eats a lot, ");
  324.     TextFace(italic);
  325.     DrawString("\ploves cats and");
  326.     MoveTo(220, 40 + 2* lineInc);
  327.     DrawString("\psmall children.");
  328.     TextFace(0);
  329.     DrawString("\p  Free to a good home.");
  330.     MoveTo(220, 40 + 3* lineInc);
  331.  
  332. // Draw two concentric QuickDraw rectangles around the text we just drew.
  333.  
  334.     GetPen(&where);
  335.     drawRect.left = 216;
  336.     drawRect.top = 30;
  337.     drawRect.right = 450;
  338.     drawRect.bottom = where.v - lineInc/2;
  339.     FrameRect(&drawRect);
  340.     InsetRect(&drawRect, -2, -2);
  341.     FrameRect(&drawRect);
  342.  
  343. /*
  344.     Calculate the center of our window, and then draw a
  345.     QuickDraw picture at that location.
  346. */
  347.     hCenter = (whichWindow->portRect.right + whichWindow->portRect.left) >>1;
  348.  
  349.     UseResFile(gAppResRefNum);
  350.     drawPict = GetPicture(r_documentPict);
  351.     UseResFile(oldResFile);
  352.  
  353.     if (drawPict != nil) 
  354.     {
  355.         picWidth = (*drawPict)->picFrame.right - (*drawPict)->picFrame.left;
  356.         picHeight = (*drawPict)->picFrame.bottom - (*drawPict)->picFrame.top;
  357.         
  358.         drawRect.top = 240;
  359.         drawRect.left = hCenter -(picWidth >>1);
  360.         drawRect.bottom = drawRect.top + picHeight;
  361.         drawRect.right = drawRect.left + picWidth;
  362.          
  363.         DrawPicture(drawPict, &drawRect);
  364.         ReleaseResource((Handle) drawPict);
  365.     }
  366.  
  367. /*
  368.     Load a QuickDraw icon, and CopyBits a bunch of them across
  369.     the page, in various colors.
  370. */
  371.     UseResFile(gAppResRefNum);
  372.     iconHdl = (Handle) GetIcon(r_documentBitmap);
  373.     UseResFile(oldResFile);
  374.  
  375.     if (iconHdl != nil)
  376.     {
  377.         MoveHHi((Handle) iconHdl);
  378.         HLock((Handle) iconHdl);
  379.         iconBitMap.rowBytes = 4;
  380.         SetRect(&iconBitMap.bounds, 0, 0, 31, 31);
  381.         iconBitMap.baseAddr = *iconHdl;
  382.         
  383.         drawRect.top = drawRect.bottom +20;
  384.         drawRect.left = 10;
  385.         drawRect.bottom = drawRect.top +31;
  386.         drawRect.right = drawRect.left +31;
  387.         
  388.         for (i = 0; i < 12; i++)
  389.         {
  390.             switch (i % 6)
  391.             {
  392.                 case 0:
  393.                     ForeColor(blackColor);
  394.                     break;
  395.                 case 1:
  396.                     ForeColor(blueColor);
  397.                     break;
  398.                 case 2:
  399.                     ForeColor(greenColor);
  400.                     break;
  401.                 case 3:
  402.                     ForeColor(redColor);
  403.                     break;
  404.                 case 4:
  405.                     ForeColor(cyanColor);
  406.                     break;
  407.                 case 5:
  408.                     ForeColor(magentaColor);
  409.                     break;
  410.             }
  411.             
  412.             GetPort(&curPort);
  413.             CopyBits(&iconBitMap, &curPort->portBits, &iconBitMap.bounds, &drawRect, srcCopy, nil);
  414.     
  415.             drawRect.left  += 40;
  416.             drawRect.right += 40;
  417.         }
  418.         
  419.         ReleaseResource(iconHdl);
  420.     }
  421.  
  422. // Draw some more QuickDraw text.  This time, blue and 24 point.
  423.  
  424.     GetFNum("\pTimes", &fNum);
  425.     TextFont(fNum);
  426.     TextSize(24);
  427.     ForeColor(blueColor);
  428.     pStr[0] = sprintf((char *) &pStr[1], "These are some typical QuickDraw objects");
  429.     MoveTo(hCenter -(StringWidth(pStr) >>1), drawRect.bottom +20);
  430.     DrawString(pStr);
  431.  
  432. // Draw some QuickDraw PicComments.
  433.  
  434.     MyDrawPicComments();
  435.  
  436. /*
  437.     Draw some more black QuickDraw text in a different font
  438.     and size, indicating the page number.
  439. */
  440.     GetFNum("\pGeneva", &fNum);
  441.     TextFont(fNum);
  442.     TextSize(12);
  443.     
  444.     ForeColor(blackColor);
  445.     pStr[0] = sprintf((char *) &pStr[1], "This is page %ld of %ld.",
  446.                       windowDoc->curPage, windowDoc->numPages);
  447.  
  448.     MoveTo(hCenter -(StringWidth(pStr) >>1), drawRect.bottom +80);
  449.     DrawString(pStr);
  450. }
  451.  
  452.  
  453. /************************************************************
  454.   MyDrawPicComments - This routine just draws some example
  455.   PicComments which will make a PostScript device display
  456.   "This was drawn on a PostScript device." and other devices
  457.   display "This was drawn on a non-PostScript device."  We
  458.   use PostScriptBegin PostScriptEnd and PostScriptHandle.
  459.  
  460. *************************************************************/
  461.  
  462. void MyDrawPicComments()
  463. {
  464.     short        fNum;
  465.  
  466. /*
  467.     Draw some QuickDraw to set the PS clip, not necessary in
  468.     this case, but if we hadn't made any QuickDraw calls yet,
  469.     the PostScript clip wouldn't get set, and *everything*
  470.     would be clipped, at least on a non-GX system.  This code,
  471.     which doesn't actually draw anything, is here as a reminder.
  472. */
  473.  
  474.     PenSize(0, 0);
  475.     MoveTo(0, 0); 
  476.     Line(0, 0);
  477.     PenSize(1, 1);
  478.  
  479. /*
  480.     PostScriptBegin tells a PostScript driver to ignore Quickdraw
  481.     calls until it receives a PostScriptEnd picture comment.
  482.     This line is ignored by non-PostScript printer drivers.
  483. */
  484.  
  485.     PicComment(PostScriptBegin, 0, nil);
  486.  
  487. /*
  488.     QuickDraw representation. These calls will only be executed by
  489.     QuickDraw printers.  Set the font to Times Italic 14 pt and then
  490.     move and draw.
  491. */
  492.  
  493.     GetFNum("\pTimes", &fNum);
  494.     TextFont(fNum);
  495.     TextSize(14);
  496.     TextFace(italic);
  497.     MoveTo(127, 227);
  498.     DrawString("\pThis was drawn on a non-PostScript device.");
  499.     TextFace(0);
  500.  
  501. /*
  502.     PostScript representation. These calls will only be executed by
  503.     PostScript printers.  We draw the same as above, sans the "non-"
  504.     and shifted left a tad.
  505. */
  506.  
  507.     MySendPostScript("\p0 760 translate 1 -1 scale");
  508.     MySendPostScript("\p/Times-Italic findfont 14 scalefont setfont");
  509.     MySendPostScript("\p135 533 moveto (This was drawn on a PostScript device.) show");
  510.  
  511. /*
  512.     PostScriptEnd tells a PostScript driver to start executing
  513.     QuickDraw calls normally again.
  514. */
  515.  
  516.     PicComment(PostScriptEnd, 0, nil);
  517. }
  518.  
  519.  
  520. /************************************************************
  521.   MySendPostScript - This routine just packages the passed
  522.   Pascal string into a handle and sends the PostScriptHandle
  523.   PicComment.
  524.  
  525. *************************************************************/
  526.  
  527. void MySendPostScript(Str255 thePostScript)
  528. {
  529.     OSErr    err;
  530.     Handle    thePSHdl;
  531.     Ptr        thePSPtr;
  532.     long    textLen;
  533.  
  534. /*
  535.     Create a handle for the passed string plus a carriage
  536.     return.  Move the string's data into the handle, stuff a
  537.     carriage return on the end, call PicComment, and finally
  538.     dispose of the handle.
  539. */
  540.     textLen = thePostScript[0];
  541.     thePSHdl = TempNewHandle(textLen +1, &err);
  542.  
  543.     if (!err)
  544.     {
  545.         thePSPtr = *thePSHdl;
  546.         BlockMove(&thePostScript[1], thePSPtr, textLen);
  547.         *(thePSPtr +textLen) = (char) 13; //carriage return.
  548.         ++textLen;
  549.  
  550.         PicComment(PostScriptHandle, textLen, thePSHdl);
  551.         DisposHandle(thePSHdl);
  552.     }
  553. }
  554.  
  555.  
  556. /************************************************************
  557.   MyAdjustMenus - This routine enables and disables our
  558.   menus and menu items.
  559.  
  560. *************************************************************/
  561.  
  562. void MyAdjustMenus()
  563. {
  564.     WindowPtr        activeWindow;
  565.     MenuHandle        appleMenu, fileMenu, editMenu, documentMenu;
  566.     MyDocumentPtr    activeDocument;
  567.     Boolean            docOpen, onFirstPage, onLastPage, maxPages, neverSaved;
  568.  
  569. /*
  570.     If we're in a GX printing dialog, don't adjust our
  571.     menus.  We've already done that.  Otherwise, enable our menus.
  572. */
  573.     if (gInPrintDialog) return;
  574.  
  575.     appleMenu = GetMHandle(mApple);
  576.     editMenu = GetMHandle(mEdit);
  577.     fileMenu = GetMHandle(mFile);
  578.     documentMenu = GetMHandle(mDocument);
  579.  
  580.     EnableItem(appleMenu, iAbout);
  581.     EnableItem(fileMenu,  iQuit);
  582.     EnableItem(fileMenu,  iNew);
  583.     EnableItem(fileMenu,  iOpen);
  584.  
  585. /*
  586.     If we have a document open, we enable certain menu items.
  587.     Otherwise, we don't.
  588. */
  589.  
  590.     activeWindow = FrontWindow();
  591.  
  592.     if (activeWindow)
  593.     {
  594.         if (((WindowPeek) activeWindow)->windowKind != userKind)
  595.             activeWindow = nil;
  596.     }
  597.  
  598.     docOpen = (activeWindow != nil);
  599.  
  600.     if (!docOpen)                                        // No document open.
  601.     {
  602.         if (gGXIsPresent)                        // Using QuickDraw GX.
  603.         {
  604.             DisableItem(fileMenu, iPrintOneCopy);
  605.             DisableItem(fileMenu, iCustomPageSetup);
  606.             DisableItem(fileMenu, iPrint);
  607.         }
  608.         else                                    // This disables "Print" in non-GX File menu.
  609.             DisableItem(fileMenu, iPrint -1);
  610.  
  611.         DisableItem(fileMenu, iClose);
  612.         DisableItem(fileMenu, iSave);
  613.         DisableItem(fileMenu, iSaveAs);
  614.         DisableItem(fileMenu, iPageSetup);
  615.         DisableItem(documentMenu, iInsertPage);
  616.         DisableItem(documentMenu, iDeletePage);
  617.         DisableItem(documentMenu, iAheadPage);
  618.         DisableItem(documentMenu, iBackPage);
  619.     }
  620.     else                                                // A document is open.
  621.     {
  622.         if (gGXIsPresent)                        // Using QuickDraw GX.
  623.         {
  624.             EnableItem(fileMenu, iPrintOneCopy);
  625.             EnableItem(fileMenu, iCustomPageSetup);
  626.             EnableItem(fileMenu, iPrint);
  627.         }
  628.         else                                    // This enables "Print" in non-GX File menu.
  629.             EnableItem(fileMenu, iPrint -1);
  630.  
  631.         EnableItem(fileMenu, iClose);
  632.         EnableItem(fileMenu, iPageSetup);
  633.         EnableItem(fileMenu, iSaveAs);
  634.  
  635. /*
  636.     Enable/disable items based on the number of pages in our document,
  637.     whether we're on the first or last page, and whether or not it's
  638.     been saved yet.
  639. */
  640.         activeDocument = MyGetDocPtr(activeWindow);
  641.  
  642.         if (activeDocument->numPages > 1)                // Got at least one page?
  643.             EnableItem(documentMenu, iDeletePage);
  644.         else
  645.             DisableItem(documentMenu, iDeletePage);
  646.  
  647.         onFirstPage = (activeDocument->curPage == 1);
  648.         onLastPage = (activeDocument->curPage == activeDocument->numPages);
  649.         maxPages = (activeDocument->numPages == kMaxPages);
  650.         neverSaved = (activeDocument->documentFSSpec.name[0] == 0);
  651.  
  652.         if (neverSaved)                                    // Never saved this document?
  653.             DisableItem(fileMenu, iSave);
  654.         else
  655.             EnableItem(fileMenu, iSave);
  656.  
  657.         if (!maxPages)                                    // Can still add more pages?
  658.             EnableItem(documentMenu, iInsertPage);
  659.         else
  660.             DisableItem(documentMenu, iInsertPage);
  661.  
  662.         if (!onLastPage)                                // Not on last page?
  663.             EnableItem(documentMenu, iAheadPage);
  664.         else
  665.             DisableItem(documentMenu, iAheadPage);
  666.  
  667.         if (!onFirstPage)                                // Not on first page?
  668.             EnableItem(documentMenu, iBackPage);
  669.         else
  670.             DisableItem(documentMenu, iBackPage);
  671.     }
  672. }
  673.  
  674.  
  675. /************************************************************
  676.   MyAdjustMenusForPrintDialogs - This routine handles
  677.   enabling and disabling menu items when we're putting up
  678.   or tearing down QuickDraw GX movable modal print dialogs.
  679.  
  680. *************************************************************/
  681.  
  682. void MyAdjustMenusForPrintDialogs(Boolean dialogGoingUp)
  683. {
  684.     MenuHandle    appleMenu, fileMenu, editMenu, documentMenu;
  685.  
  686.     appleMenu = GetMHandle(mApple);
  687.     fileMenu = GetMHandle(mFile);
  688.     editMenu = GetMHandle(mEdit);
  689.     documentMenu = GetMHandle(mDocument);
  690.  
  691. /*
  692.     If a print dialog is about to be displayed, disable our
  693.     "About" item, our File menu, and our Document menu.
  694.     Otherwise, enable them since a print dialog just came down.
  695. */
  696.     if (dialogGoingUp)
  697.     {
  698.         DisableItem(appleMenu, iAbout);
  699.         DisableItem(fileMenu, 0);
  700.         DisableItem(documentMenu, 0);
  701.         HiliteMenu(0);
  702.     }
  703.     else
  704.     {
  705.         EnableItem(appleMenu, iAbout);
  706.         EnableItem(fileMenu, 0);
  707.         DisableItem(editMenu, 0);            // *Sigh!*  Our app's lazy.
  708.         EnableItem(documentMenu, 0);
  709.     }
  710.  
  711.     DrawMenuBar();
  712.     gInPrintDialog = dialogGoingUp;
  713. }
  714.  
  715.  
  716. /************************************************************
  717.   MyDoMenuCommand - This routine handles the dispatching of
  718.   our menu requests.
  719.  
  720. *************************************************************/
  721.  
  722. void MyDoMenuCommand(long menuResult)
  723. {
  724.     short                menuID, menuItem;
  725.     long                curPage, numPages, newPage;
  726.     Str255                daName;
  727.     OSErr                err;
  728.     WindowPtr            activeWindow;
  729.     MyDocumentPtr        activeDocument, aDocument;
  730.  
  731.     menuID = menuResult >>16;
  732.     menuItem = menuResult & 0x0000FFFF;
  733.     activeWindow = FrontWindow();
  734.     activeDocument = MyGetDocPtr(activeWindow);
  735.  
  736. /*
  737.     Because we delete two items from our File menu if we're not
  738.     using QuickDraw GX, we may need to convert the menu item
  739.     before servicing it.  MyConvertMenuItem handles this.
  740. */
  741.     MyConvertMenuItem(&menuID, &menuItem);
  742.  
  743.     switch (menuID)
  744.     {
  745.         case mApple:
  746.             switch (menuItem)
  747.             {
  748.                 case iAbout:                    // About.
  749.  
  750.                     Alert(r_About, nil);
  751.                     break;
  752.                 
  753.                 default:                        // DAs, etc.
  754.  
  755.                     GetItem(GetMHandle(mApple), menuItem, daName);
  756.                     OpenDeskAcc(daName);
  757.                     break;
  758.             }
  759.             break;
  760.             
  761.             case mFile:
  762.                 switch (menuItem)
  763.                 {                        
  764.                     case iNew:                    // New or Open.
  765.                     case iOpen:
  766.  
  767.                         err = MyCreateDocument(kDefaultTitle, &aDocument);
  768.  
  769.                         if ((err == noErr) && (menuItem == iOpen))
  770.                         {
  771.                             err = MyLoadDocument(aDocument);
  772.  
  773.                             if (err != noErr)
  774.                                 MyDisposeDocument(aDocument);
  775.                         }
  776.                         
  777.                         if (err == noErr)
  778.                         {
  779.                             ShowWindow(aDocument->documentWindow);
  780.                             SelectWindow(aDocument->documentWindow);
  781.                             MyAdjustMenus();
  782.                         }
  783.                         break;
  784.                                                 
  785.                     case iClose:                // Close.
  786.  
  787.                         MyDisposeDocument(activeDocument);
  788.                         break;
  789.                                                 
  790.                     case iSave:                    // Save or Save As.
  791.                     case iSaveAs:
  792.  
  793.                         err = MySaveDocument(activeDocument, (menuItem == iSaveAs));
  794.                         break;
  795.         
  796.                     case iPageSetup:            // Page Setup.
  797.  
  798.                         if (MyDoPageSetup(activeDocument))
  799.                             MyRepaginateDoc(activeDocument);
  800.                         break;
  801.  
  802.                     case iCustomPageSetup:        // Custom Page Setup (only with GX).
  803.  
  804.                         if (MyDoCustomPageSetup(activeDocument))
  805.                             MyRepaginateDoc(activeDocument);
  806.                         break;
  807.  
  808.                     case iPrint:                // Print.
  809.  
  810.                         err = MyPrintDocument(activeDocument);
  811.                         break;
  812.  
  813.                     case iPrintOneCopy:            // Print one copy (only with GX).
  814.  
  815.                         err = MyPrintOneCopy(activeDocument);
  816.                         break;
  817.  
  818.                     case iQuit:                    // Quitting.
  819.  
  820.                         gQuitting = true;
  821.                         break;
  822.                 }
  823.                 break;
  824.                 
  825.             case mEdit:  // If this were a real app, blah, blah, blah.
  826.                 break;
  827.                 
  828.             case mDocument:
  829.                 switch (menuItem)
  830.                 {                        
  831.                     case iInsertPage:            // Insert a page.
  832.                             
  833.                             newPage = activeDocument->curPage;
  834.                             MyInsertPage(activeDocument, &newPage);
  835.                             activeDocument->curPage = newPage;
  836.                             SetPort(activeWindow);
  837.                             EraseRect(&activeWindow->portRect);
  838.                             InvalRect(&activeWindow->portRect);
  839.                         break;
  840.                                                 
  841.                     case iDeletePage:            // Delete current page.
  842.                             
  843.                             curPage = activeDocument->curPage;
  844.                             numPages = activeDocument->numPages;
  845.  
  846.                             if (numPages > 1)
  847.                             {
  848.                                 MyDisposePage(activeDocument, curPage);
  849.  
  850.                                 if (curPage == numPages)
  851.                                     curPage = --activeDocument->curPage;
  852.                                 
  853.                                 SetPort(activeWindow);
  854.                                 EraseRect(&activeWindow->portRect);
  855.                                 InvalRect(&activeWindow->portRect);
  856.                             }
  857.                         break;
  858.                                                 
  859.                     case iAheadPage:            // Display ahead one page.
  860.                             
  861.                             curPage = activeDocument->curPage;
  862.                             numPages = activeDocument->numPages;
  863.  
  864.                             if (curPage < numPages)
  865.                             {
  866.                                 ++activeDocument->curPage;
  867.                                 
  868.                                 SetPort(activeWindow);
  869.                                 EraseRect(&activeWindow->portRect);
  870.                                 InvalRect(&activeWindow->portRect);
  871.                             }
  872.                         break;
  873.                                                 
  874.                     case iBackPage:                // Display back one page.
  875.                             
  876.                             curPage = activeDocument->curPage;
  877.  
  878.                             if (curPage > 1)
  879.                             {
  880.                                 --activeDocument->curPage;
  881.                                 
  882.                                 SetPort(activeWindow);
  883.                                 EraseRect(&activeWindow->portRect);
  884.                                 InvalRect(&activeWindow->portRect);
  885.                             }
  886.                         break;
  887.                 }
  888.                 break;
  889.     }
  890.  
  891.     HiliteMenu(0);
  892. }
  893.  
  894.  
  895. /************************************************************
  896.   MyConvertMenuItem - This routine converts our menu item
  897.   IDs, if we aren't running QuickDraw GX.  Since our
  898.   MyDoMenuCommand routine switches off of the QuickDraw GX
  899.   menu IDs, we may need to adjust them.  (Remember, when
  900.   QuickDraw GX is not running we remove the "Print One Copy"
  901.   and "Custom Page Setup" menu items.
  902.  
  903. *************************************************************/
  904.  
  905. void MyConvertMenuItem(short *menuID, short *menuItem)
  906. {
  907.     if (!gGXIsPresent)                        // QuickDraw GX isn't running?
  908.     {                                        // then…
  909.         if (*menuItem == iCustomPageSetup)    // If "Custom Page Setup" is selected,
  910.             *menuItem = iPrint;                // it's really "Print."
  911.         else                                // and…
  912.             if (*menuItem == iPrintOneCopy)    // If "Print One Copy" is selected,
  913.                 *menuItem = iQuit;            // it's really "Quit."
  914.     }
  915. }
  916.  
  917.  
  918. /************************************************************
  919.   MyGetDocPtr - This routine returns a pointer to the
  920.   private document structure our application attaches to
  921.   its windows.
  922.  
  923. *************************************************************/
  924.  
  925. MyDocumentPtr MyGetDocPtr(WindowPtr whichWindow)
  926. {
  927.     MyDocumentPtr    windowsDocument = nil;
  928.  
  929.     if (whichWindow != nil)
  930.         windowsDocument = (MyDocumentPtr) GetWRefCon(whichWindow);
  931.  
  932.     return windowsDocument;
  933. }
  934.  
  935.